/*
 * Copyright (C) 2015-2017 Jacksgong(blog.dreamtobe.cn)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.asen.libcommon.widget.keyboard.util;

import android.app.Activity;
import android.view.MotionEvent;
import android.view.View;

import com.asen.libcommon.widget.keyboard.handler.KPSwitchFSPanelLayoutHandler;
import com.asen.libcommon.widget.keyboard.handler.KPSwitchPanelLayoutHandler;
import com.asen.libcommon.widget.keyboard.handler.KPSwitchRootLayoutHandler;

/**
 * @author : asenLiang
 * @date   : 2020/01/8
 * @e-mail : liangAisiSen@163.com
 * @desc   : 这个util将帮助您轻松准确地控制面板和键盘，避免布局冲突。
 *           <p/>
 *           此实用工具只支持应用层封装，有关如何解决布局冲突的详细信息请参考  {@link KPSwitchRootLayoutHandler}、{@link KPSwitchPanelLayoutHandler}、{@link KPSwitchFSPanelLayoutHandler}
 *           <p/>
 *           Any problems: https://github.com/Jacksgong/JKeyboardPanelSwitch
 *
 *           @see KPSwitchRootLayoutHandler
 *           @see KPSwitchPanelLayoutHandler
 *           @see KPSwitchFSPanelLayoutHandler
 */
public class KPSwitchConflictUtil {

    // whether current activity is in multi window mode
    private static boolean mIsInMultiWindowMode = false;

    /**
     * @see #attach(View, View, View, SwitchClickListener)
     */
    public static void attach(final View panelLayout,
            /* Nullable **/final View switchPanelKeyboardBtn,
            /* Nullable **/final View focusView) {
        attach(panelLayout, switchPanelKeyboardBtn, focusView, null);
    }

    /**
     * 将{@code switchPanelKeyboardBtn}和{@code focusView}的操作附加到非布局冲突。
     * <p/>
     * 您不必使用此方法来附加非布局冲突，换句话说，您可以使用invoke方法手动附加该操作：{@link #showPanel(View)}、
     * {@link #showKeyboard(View, View)}、{@link #hidePanelAndKeyboard(View)}，在不调用此方法进行附加的情况下，
     * 如果您的活动是全屏主题，请确保您的面板布局是{@link View#INVISIBLE}，然后键盘才会显示出来。
     *
     * @param panelLayout            面板布局.
     * @param switchPanelKeyboardBtn 视图将用于触发面板和键盘之间的切换。
     * @param focusView              视图将被聚焦或失去焦点。
     * @param switchClickListener    click侦听器用于侦听的click事件{@code switchPanelKeyboardBtn}。
     * @see #attach(View, View, SwitchClickListener, SubPanelAndTrigger...)
     */
    public static void attach(final View panelLayout,
            /* Nullable **/final View switchPanelKeyboardBtn,
            /* Nullable **/final View focusView,
            /* Nullable **/final SwitchClickListener switchClickListener) {
        final Activity activity = (Activity) panelLayout.getContext();

        if (switchPanelKeyboardBtn != null) {
            switchPanelKeyboardBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    final boolean switchToPanel = switchPanelAndKeyboard(panelLayout, focusView);
                    if (switchClickListener != null) {
                        switchClickListener.onClickSwitch(v, switchToPanel);
                    }
                }
            });
        }

        if (isHandleByPlaceholder(activity)) {
            focusView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        /*
                         * 显示假空键盘同高面板，以解决键盘显示时的冲突。
                         * @see KPSwitchConflictUtil#showKeyboard(View, View)
                         */
                        panelLayout.setVisibility(View.INVISIBLE);
                    }
                    return false;
                }
            });
        }
    }

    /**
     * 相同的 {@link #attach(View, View, SwitchClickListener, SubPanelAndTrigger...)}.
     */
    public static void attach(final View panelLayout,
                              final View focusView,
                              SubPanelAndTrigger... subPanelAndTriggers) {
        attach(panelLayout, focusView, null, subPanelAndTriggers);
    }

    /**
     * 如果在{@code panelLayout}中有多个子面板，可以使用此方法简单地将它们附加到非布局冲突中。否则，您可以
     * 使用{@link #attach(View, View, View)} 或 {@link #attach(View, View, View, SwitchClickListener)}.
     *
     * @param panelLayout         面板的布局
     * @param focusView           视图将被聚焦或失去焦点
     * @param switchClickListener 侦听器用于监听面板显示还是键盘显示，并切换面板/键盘状态
     * @param subPanelAndTriggers 触发器切换视图的数组和绑定触发器切换视图的子面板
     */
    public static void attach(final View panelLayout,
                              final View focusView,
                              /** Nullable **/final SwitchClickListener switchClickListener,
                              SubPanelAndTrigger... subPanelAndTriggers) {
        final Activity activity = (Activity) panelLayout.getContext();

        for (SubPanelAndTrigger subPanelAndTrigger : subPanelAndTriggers) {

            bindSubPanel(subPanelAndTrigger, subPanelAndTriggers, focusView, panelLayout, switchClickListener);
        }

        if (com.asen.libcommon.widget.keyboard.util.KPSwitchConflictUtil.isHandleByPlaceholder(activity)) {
            focusView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        /**
                         * 显示假空键盘相同高度面板，以修复键盘显示时的冲突.
                         * @see com.asen.libcommon.widget.keyboard.util.KPSwitchConflictUtil#showKeyboard(View, View)
                         */
                        panelLayout.setVisibility(View.INVISIBLE);
                    }
                    return false;
                }
            });
        }
    }

    /**
     * @see #attach(View, View, SwitchClickListener, SubPanelAndTrigger...)
     */
    public static class SubPanelAndTrigger {
        /** 子面板视图是面板布局的子视图。 */
        final View subPanelView;
        /** 触发器视图用于触发 {@code subPanelView} 可见状态。 */
        final View triggerView;

        public SubPanelAndTrigger(View subPanelView, View triggerView) {
            this.subPanelView = subPanelView;
            this.triggerView = triggerView;
        }
    }

    /**
     * 显示具有非布局冲突的面板（如果显示键盘，则自动隐藏键盘）
     *
     * @param panelLayout 面板的布局
     * @see KPSwitchPanelLayoutHandler
     */
    public static void showPanel(final View panelLayout) {
        final Activity activity = (Activity) panelLayout.getContext();
        panelLayout.setVisibility(View.VISIBLE);
        if (activity.getCurrentFocus() != null) {
            com.asen.libcommon.widget.keyboard.util.KeyboardUtil.hideKeyboard(activity.getCurrentFocus());
        }
    }

    /**
     * 显示具有非布局冲突的键盘。（如果显示面板，则自动隐藏面板）
     *
     * @param panelLayout 面板的布局
     * @param focusView   视图将会聚焦
     */
    public static void showKeyboard(final View panelLayout, final View focusView) {
        final Activity activity = (Activity) panelLayout.getContext();

        com.asen.libcommon.widget.keyboard.util.KeyboardUtil.showKeyboard(focusView);
        if (isHandleByPlaceholder(activity)) {
            panelLayout.setVisibility(View.INVISIBLE);
        } else if (mIsInMultiWindowMode) {
            panelLayout.setVisibility(View.GONE);
        }
    }

    /**
     * 如果显示键盘，则显示{@code panelLayout}，并隐藏具有非布局冲突的键盘
     * <p/>
     * 如果显示面板，则显示键盘，并隐藏带有非布局冲突的{@code panelLayout}。
     * <p/>
     * 如果面板和键盘都隐藏起来了。然后显示带有非布局冲突的{@code panelLayout}。
     *
     * @param panelLayout 面板的布局.
     * @param focusView   视图将被聚焦或失去焦点
     * @return 如果为true，则切换到显示{@code panelLayout}；如果为false，则切换到显示键盘。
     */
    public static boolean switchPanelAndKeyboard(final View panelLayout, final View focusView) {
        boolean switchToPanel = panelLayout.getVisibility() != View.VISIBLE;
        if (!switchToPanel) {
            showKeyboard(panelLayout, focusView);
        } else {
            showPanel(panelLayout);
        }

        return switchToPanel;
    }

    /**
     * 隐藏面板和键盘
     *
     * @param panelLayout 面板的布局
     */
    public static void hidePanelAndKeyboard(final View panelLayout) {
        final Activity activity = (Activity) panelLayout.getContext();

        final View focusView = activity.getCurrentFocus();
        if (focusView != null) {
            com.asen.libcommon.widget.keyboard.util.KeyboardUtil.hideKeyboard(activity.getCurrentFocus());
            focusView.clearFocus();
        }

        panelLayout.setVisibility(View.GONE);
    }

    /**
     * 此侦听器用于侦听视图的click事件，该视图接收到click事件以在面板和键盘之间切换。
     *
     * @see #attach(View, View, View, SwitchClickListener)
     */
    public interface SwitchClickListener {
        /**
         * @param v             单击的视图.
         * @param switchToPanel 如果为true，则切换到显示面板；如果为false，则切换到显示键盘。
         */
        void onClickSwitch(View v, boolean switchToPanel);
    }

    /**
     * @param isFullScreen        是否为全屏主题.
     * @param isTranslucentStatus 是否处于半透明状态主题。
     * @param isFitsSystem        根视图（内容视图的子视图）是否在{@code getFitSystemWindow（）}中等于true。
     * @return 是否通过显示面板占位符来处理冲突，否则，延迟处理可见或消失的面板。
     */
    public static boolean isHandleByPlaceholder(boolean isFullScreen, boolean isTranslucentStatus,
                                                boolean isFitsSystem) {
        return isFullScreen || (isTranslucentStatus && !isFitsSystem);
    }

    static boolean isHandleByPlaceholder(final Activity activity) {
        return isHandleByPlaceholder(ViewUtil.isFullScreen(activity),
                ViewUtil.isTranslucentStatus(activity), ViewUtil.isFitsSystemWindows(activity));
    }

    private static void bindSubPanel(final SubPanelAndTrigger subPanelAndTrigger,
                                     final SubPanelAndTrigger[] subPanelAndTriggers,
                                     final View focusView, final View panelLayout,
            /* Nullable */final SwitchClickListener switchClickListener) {

        final View triggerView = subPanelAndTrigger.triggerView;
        final View boundTriggerSubPanelView = subPanelAndTrigger.subPanelView;

        triggerView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Boolean switchToPanel = null;
                if (panelLayout.getVisibility() == View.VISIBLE) {
                    // panel is visible.

                    if (boundTriggerSubPanelView.getVisibility() == View.VISIBLE) {

                        // bound-trigger panel is visible.
                        // to show keyboard.
                        com.asen.libcommon.widget.keyboard.util.KPSwitchConflictUtil.showKeyboard(panelLayout, focusView);
                        switchToPanel = false;

                    } else {
                        // bound-trigger panel is invisible.
                        // to show bound-trigger panel.
                        showBoundTriggerSubPanel(boundTriggerSubPanelView, subPanelAndTriggers);
                    }
                } else {
                    // panel is gone.
                    // to show panel.
                    com.asen.libcommon.widget.keyboard.util.KPSwitchConflictUtil.showPanel(panelLayout);
                    switchToPanel = true;

                    // to show bound-trigger panel.
                    showBoundTriggerSubPanel(boundTriggerSubPanelView, subPanelAndTriggers);
                }

                if (switchClickListener != null && switchToPanel != null) {
                    switchClickListener.onClickSwitch(v, switchToPanel);
                }
            }
        });
    }

    private static void showBoundTriggerSubPanel(final View boundTriggerSubPanelView,
                                                 final SubPanelAndTrigger[] subPanelAndTriggers) {
        // to show bound-trigger panel.
        for (SubPanelAndTrigger panelAndTrigger : subPanelAndTriggers) {
            if (panelAndTrigger.subPanelView != boundTriggerSubPanelView) {
                // other sub panel.
                panelAndTrigger.subPanelView.setVisibility(View.GONE);
            }
        }
        boundTriggerSubPanelView.setVisibility(View.VISIBLE);
    }

    public static void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
        mIsInMultiWindowMode = isInMultiWindowMode;
    }

}
